package com.example.customclassloader;

import org.apache.commons.collections.ListUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.stereotype.Component;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author xionglei
 * @version 1.0.0
 * 2021年08月18日 17:14
 */
@Component
public class ClassContainer {


    private static final Map<String, String> jarPaths;

    static {

        final String pathStr = System.getProperty("java.class.path");

        final String[] allPaths = pathStr.split(";");
        System.out.println("classpath ================");
        System.out.println(pathStr);
        final Map<String, String> paths = new HashMap();

        // 创建jarName与jar路径的映射

        final char separator = File.separatorChar;
        for (String path : allPaths) {

            final int i = path.lastIndexOf(separator);
            if (i >= path.length()) {
                continue;
            }
            final String jarName = path.substring(i + 1);

            paths.put(jarName, path);
        }

        jarPaths = Collections.unmodifiableMap(paths);
    }

    private ChildFirstClassLoader delegate;

    public ClassContainer() {}

    public ClassContainer(ClassLoader classloader, String... jarNames) {
        if (jarNames == null || jarNames.length == 0) {
            return;
        }
        ArrayList<URL> urlList = new ArrayList<>();
        String pathStr = System.getProperty("java.class.path");
        String sunBootLibraryPath = System.getProperty("sun.boot.library.path");
        sunBootLibraryPath = sunBootLibraryPath.substring(0, sunBootLibraryPath.lastIndexOf(File.separatorChar) +1);
        List<String> pathList = Arrays.asList(pathStr.split(";"));
        String finalSunBootLibraryPath = sunBootLibraryPath;
        List<URL> jreJarUrls = pathList.stream().filter(s -> s.contains(finalSunBootLibraryPath)).map(s -> {
            try {
                return new File(s).toURI().toURL();
            } catch (MalformedURLException e) {
                throw new DelegateCreateException("cannot create classloader delegate", e);
            }
        }).collect(Collectors.toList());
        urlList.addAll(jreJarUrls);
        try {
            for (int i = 0; i < jarNames.length; i++) {
                String jarName = jarNames[i];
                final String spec = jarPaths.get(jarName);
                if (spec == null) {
                    throw new JarNotExistsException("the jar [" + jarName + "] is not exist in your elasspath, please check");
                }
                urlList.add(new File(spec).toURI().toURL());
            }

            this.delegate = new ChildFirstClassLoader(urlList.toArray(new URL[urlList.size()]), classloader);
        } catch (MalformedURLException e) {
            throw new DelegateCreateException("cannot create classloader delegate", e);
        }
    }

    public Class<?> getClass(String name) throws ClassNotFoundException {
        return delegate.loadClass(name);
    }

    private static final class JarNotExistsException extends RuntimeException {
        public JarNotExistsException(String message) {
            super(message);
        }
    }

    /**
     * 委派异常
     */
    private static final class DelegateCreateException extends RuntimeException {
        public DelegateCreateException(String message, Throwable t) {
            super(message, t);
        }
    }
}


